#pragma once

#include <type_traits>
#include <cctype>
#include <string>

namespace dave
{
	namespace detail
	{

		template < typename _Type >
		struct type_traits
		{
			typedef typename _Type             value_type;
			typedef typename value_type*       pointer;
			typedef typename value_type&       reference;
			typedef typename value_type const* const_pointer;
			typedef typename value_type const& const_reference;
			typedef typename std::size_t       size_type;
			typedef typename std::ptrdiff_t    difference_type;
		};

		template < typename _Type, bool _CaseSensitive = false, typename _Traits = type_traits< _Type > >
		struct char_traits
		{
			typedef typename _Traits::value_type      value_type;
			typedef typename _Traits::pointer         pointer;
			typedef typename _Traits::reference       reference;
			typedef typename _Traits::const_pointer	  const_pointer;
			typedef typename _Traits::const_reference const_reference;
			typedef typename _Traits::size_type       size_type;
			typedef typename _Traits::difference_type difference_type;

			static bool less_than(value_type in_lhs, value_type in_rhs)
			{
				return (in_lhs < in_rhs);
			}

			static bool equal(value_type in_lhs, value_type in_rhs)
			{
				return (in_lhs == in_rhs);
			}

			static int compare(const_pointer in_lhs, const_pointer in_rhs, int in_length)
			{
				return memcmp(reinterpret_cast<const_pointer>(in_lhs), reinterpret_cast<const_pointer>(in_rhs), in_length);
			}
		};

		template < typename _Type, typename _Traits >
		struct char_traits< _Type, true, _Traits >
		{
			typedef typename _Traits::value_type      value_type;
			typedef typename _Traits::pointer         pointer;
			typedef typename _Traits::reference       reference;
			typedef typename _Traits::const_pointer	  const_pointer;
			typedef typename _Traits::const_reference const_reference;
			typedef typename _Traits::size_type       size_type;
			typedef typename _Traits::difference_type difference_type;

			static bool less_than(value_type in_lhs, value_type in_rhs)
			{
				return (tolower(in_lhs) < tolower(in_rhs));
			}

			static bool equal(value_type in_lhs, value_type in_rhs)
			{
				return (std::tolower(in_lhs) == tolower(in_rhs));
			}

			static int compare(const_pointer in_lhs, const_pointer in_rhs, int in_length)
			{
				return memcmp(reinterpret_cast<const_pointer>(in_lhs), reinterpret_cast<const_pointer>(in_rhs), in_length);
			}
		};/**/
	}
}